package org.jetlinks.pro.auth.web;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.hswebframework.web.api.crud.entity.QueryOperation;
import org.hswebframework.web.api.crud.entity.QueryParamEntity;
import org.hswebframework.web.api.crud.entity.TreeSupportEntity;
import org.hswebframework.web.authorization.annotation.*;
import org.hswebframework.web.crud.service.ReactiveCrudService;
import org.hswebframework.web.system.authorization.defaults.service.terms.DimensionTerm;
import org.jetlinks.pro.assets.AssetsHolder;
import org.jetlinks.pro.auth.entity.OrganizationEntity;
import org.jetlinks.pro.auth.service.OrganizationService;
import org.jetlinks.pro.auth.tenant.OrganizationAssetType;
import org.jetlinks.pro.tenant.TenantMember;
import org.jetlinks.pro.tenant.annotation.TenantAssets;
import org.jetlinks.pro.tenant.crud.TenantAccessCrudController;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Collections;
import java.util.List;

@RequestMapping("/organization")
@RestController
@Resource(id = "organization", name = "机构管理")
@Tag(name = "机构管理")
@TenantAssets(type = "organization")
public class OrganizationController implements TenantAccessCrudController<OrganizationEntity, String> {

    private final OrganizationService organizationService;

    public OrganizationController(OrganizationService organizationService) {
        this.organizationService = organizationService;
    }

    private Flux<OrganizationEntity> queryAll() {
        return AssetsHolder
            .injectQueryParam(QueryParamEntity
                                  .newQuery()
                                  .orderByAsc(OrganizationEntity::getSortIndex)
                                  .noPaging()
                                  .getParam(), OrganizationAssetType.organization, OrganizationEntity::getId)
            .flatMapMany(organizationService::query);
    }

    @GetMapping("/_all/tree")
    @Authorize(merge = false)
    @Operation(summary = "获取全部机构信息(树结构)")
    @TenantAssets(ignore = true)
    public Flux<OrganizationEntity> getAllOrgTree() {
        return queryAll()
            .collectList()
            .flatMapIterable(list -> TreeSupportEntity.list2tree(list, OrganizationEntity::setChildren));
    }

    @GetMapping("/_all")
    @Authorize(merge = false)
    @Operation(summary = "获取全部机构信息")
    @TenantAssets(ignore = true)
    public Flux<OrganizationEntity> getAllOrg() {
        return queryAll();
    }

    @GetMapping("/_query/_children/tree")
    @QueryAction
    @QueryOperation(summary = "查询机构列表(包含子机构)树结构")
    @TenantAssets
    public Mono<List<OrganizationEntity>> queryChildrenTree(@Parameter(hidden = true) QueryParamEntity entity) {
        return organizationService.queryIncludeChildrenTree(entity);
    }

    @GetMapping("/_query/_children")
    @QueryAction
    @QueryOperation(summary = "查询机构列表(包含子机构)")
    @TenantAssets
    public Flux<OrganizationEntity> queryChildren(@Parameter(hidden = true) QueryParamEntity entity) {
        return organizationService.queryIncludeChildren(entity);
    }

    @PostMapping("/{id}/users/_bind")
    @ResourceAction(id = "bind-user", name = "绑定用户")
    @TenantAssets
    @Operation(summary = "绑定用户到机构")
    public Mono<Integer> bindUser(@Parameter(description = "机构ID") @PathVariable String id,
                               @Parameter(description = "用户ID")
                               @RequestBody Mono<List<String>> userId) {

        return Mono
            .zip(
                userId,
                //当前用户所在租户
                TenantMember
                    .currentAll()
                    .map(member->member.getTenant().getId())
                    .collectList()
                    .defaultIfEmpty(Collections.emptyList())
            )
            .flatMap(tp2 -> organizationService.bindUser(id, tp2.getT1(), tp2.getT2()));

    }

    @PostMapping("/{id}/users/_unbind")
    @ResourceAction(id = "unbind-user", name = "解绑用户")
    @TenantAssets
    @Operation(summary = "从机构解绑用户")
    public Mono<Integer> unbindUser(@Parameter(description = "机构ID")@PathVariable String id,
                                 @Parameter(description = "用户ID")
                                 @RequestBody Mono<List<String>> userId) {
        return Mono
            .zip(
                userId,
                //当前用户所在租户,只能解绑当前用户所在租户里用户的机构信息
                TenantMember
                    .currentAll()
                    .map(member->member.getTenant().getId())
                    .collectList()
                    .defaultIfEmpty(Collections.emptyList())
            )
            .flatMap(tp2 -> organizationService.unbindUser(id, tp2.getT1(), tp2.getT2()));
    }

    @Override
    public ReactiveCrudService<OrganizationEntity, String> getService() {
        return organizationService;
    }
}
